package sm

import (
	"fmt"
	"strings"
	"time"

	"pac/conf"

	"github.com/alecthomas/log4go"
	"github.com/xft/modbus"
)

// SmartMeter 处理 modbus 设备
func SmartMeter(background bool) {
	if len(conf.DeviceModbusMaster.DevPath) == 0 {
		return
	}
	cli := modbus.NewRTUClient2(
		conf.DeviceModbusMaster.DevPath,
		conf.DeviceModbusMaster.BaudRate,
		conf.DeviceModbusMaster.DataBits,
		conf.DeviceModbusMaster.Parity,
		conf.DeviceModbusMaster.StopBits,
		time.Second*5,
	)
	err := cli.Connect()
	if err != nil {
		log4go.Error("connect to %v: %v", conf.DeviceModbusMaster.DevPath, err)
		return
	}
	defer cli.Close()

	cli.SetSlaveID(1)

	if background {
		go readWorker(cli)
	} else {
		readWorker(cli)
	}
}

func readWorker(cli modbus.Client) {
	for {
		readOnce(cli)
	}
}

func readOnce(cli modbus.Client) {
	readMeasure(cli)
	readWave(cli)
}

func readMeasure(cli modbus.Client) {
	const address uint16 = 100
	const quantity uint16 = 34

	values, err := cli.ReadHoldingRegisters(address, quantity)
	if err != nil {
		log4go.Error("ReadHoldingRegisters(%v, %v): %v", address, quantity, err)
		return
	}

	// Three-phase voltage
	tpv := float32(values[0]) / 100
	// Three-phase current
	tpi := float32(values[1]) / 100
	// Three-phase frequency
	tpf := float32(values[2]) / 100
	// Three-phase active
	tpa := float32(values[3]) / 100
	// Three-phase reactive
	tpr := float32(values[4]) / 100
	// Three-phase power factor
	tppf := float32(values[5]) / 100

	// Phase A voltage voltage
	pAv := float32(values[6]) / 100
	// Phase A current
	pAi := float32(values[7]) / 100
	// Phase A frequency
	pAf := float32(values[8]) / 100
	// Phase A active
	pAa := float32(values[9]) / 100
	// Phase A reactive
	pAr := float32(values[10]) / 100
	// Phase A power factor
	pApf := float32(values[11]) / 100

	// Phase B voltage voltage
	pBv := float32(values[12]) / 100
	// Phase B current
	pBi := float32(values[13]) / 100
	// Phase B frequency
	pBf := float32(values[14]) / 100
	// Phase B active
	pBa := float32(values[15]) / 100
	// Phase B reactive
	pBr := float32(values[16]) / 100
	// Phase B power factor
	pBpf := float32(values[17]) / 100

	// Phase C voltage voltage
	pCv := float32(values[18]) / 100
	// Phase C current
	pCi := float32(values[19]) / 100
	// Phase C frequency
	pCf := float32(values[20]) / 100
	// Phase C active
	pCa := float32(values[21]) / 100
	// Phase C reactive
	pCr := float32(values[22]) / 100
	// Phase C power factor
	pCpf := float32(values[23]) / 100

	// Three-phase apparent power
	tpap := float32(values[24]) / 100
	// TPhase A apparent power
	pAap := float32(values[26]) / 100
	// Phase B apparent power
	pBap := float32(values[26]) / 100
	// Phase C apparent power
	pCap := float32(values[27]) / 100

	// Three-phase active energy
	tpae := uint32(values[28]) | (uint32(values[29]) << 16)
	// Three-phase reactive energy
	tpre := uint32(values[30]) | (uint32(values[31]) << 16)
	// Three-phase apparent energy
	tpappe := uint32(values[32]) | (uint32(values[33]) << 16)

	log4go.Info("Phase A: voltage: %v, current: %v, frequency: %v, active: %v, reactive: %v, power factor: %v, apparent power: %v",
		pAv, pAi, pAf, pAa, pAr, pApf, pAap)
	log4go.Info("Phase B: voltage: %v, current: %v, frequency: %v, active: %v, reactive: %v, power factor: %v, apparent power: %v",
		pBv, pBi, pBf, pBa, pBr, pBpf, pBap)
	log4go.Info("Phase C: voltage: %v, current: %v, frequency: %v, active: %v, reactive: %v, power factor: %v, apparent power: %v",
		pCv, pCi, pCf, pCa, pCr, pCpf, pCap)

	log4go.Info("Three-phase: voltage: %v, current: %v, frequency: %v, active: %v, reactive: %v, power factor: %v, apparent power: %v, active energy: %v, reactive energy: %v, apparent energy: %v",
		tpv, tpi, tpf, tpa, tpr, tppf, tpap, tpae, tpre, tpappe)
}

func readWave(cli modbus.Client) {
	var address uint16 = 0x100
	var quantity uint16 = 65

	var values []uint16

	res, err := cli.ReadHoldingRegisters(address, quantity)
	if err != nil {
		log4go.Error("ReadHoldingRegisters(%v, %v): %v", address, quantity, err)
		return
	}

	values = append(values, res...)

	quantity = 64
	for i := 1; i < 8; i++ {
		address += (quantity + 1) * uint16(i)
		res, err = cli.ReadHoldingRegisters(address, quantity)
		if err != nil {
			log4go.Error("ReadHoldingRegisters(%v, %v): %v", address, quantity, err)
			return
		}

		values = append(values, res...)
	}

	log4go.Info("S: %v", values[0])
	var sb strings.Builder
	waveValues := values[1:]
	for i := 0; i < len(waveValues); i += 2 {
		if i != 0 && i&0xF == 0 {
			log4go.Info("Wave: %v", sb.String())
			sb.Reset()
		}
		sb.WriteString(fmt.Sprintf("%6dV %6dA ", int16(waveValues[i]), int16(waveValues[i+1])))
	}
	log4go.Info("Wave: %v", sb.String())
}
